#pragma once
#include "IBarrier.h"
#include "cpp_framework.h"

using namespace CMDR;

static int ThreadID = 0;

class STBThreadLocal : public ThreadLocal<int>
{
public:
	int initialValue() { return 0; }
};

class STBThreadLocalID : public ThreadLocal<int>
{
public:
	int initialValue() { return 0; }
};

//volatile int global_sense; // global barrier sense

class StaticTreeBarrier :
	public IBarrier
{
friend class Node;
public: // StaticTreeBarrier Class

	class Node
	{
	friend class StaticTreeBarrier;
	public: // Node Class

		void initNode(int fanout, Node* parent)
		{
			//global_sense = 1; // set global to 1 since all threads would get NULL==0 as init.
			this->children = fanout;
			this->childCount.set(fanout);
			this->parent = parent;
		}
	
		/*
		* C'tor
		* parent - the parent node of this new node.
		*/
		Node(Node* parent, const int count)
		{
			initNode(count, parent);
		}


		// C'tor to construct root node
		Node(const int fanout)
		{
			initNode(fanout,NULL);
		}
	
		Node() {
			initNode(0, NULL);
		}

		// d'tor
		virtual ~Node(void)
		{
			
		}
	
		void await();

		inline void childDone()
		{
			childCount.getAndDecrement();
		}

    private: // Node Class
		Node* parent;
		//volatile int global_sense; // global barrier sense

	    int children; // number of children
	    AtomicInteger childCount; // number of children incomplete

	}; // end of inner class Node

	StaticTreeBarrier(int numOfThreads, int fanout)
	{
		_numOfThreads = numOfThreads;
		_radix = fanout;
		_leaf = new Node*[numOfThreads];
		_leaves = 0;

   // nodes = 0; <<< _leaf
    //this.node = new Node[numOfThreads];  << levaes
   		
		global_sense = 1; // set global to 1 since all threads would get NULL==0 as init.
		int depth;
		depth = 0;
		int n = _numOfThreads;
		while (n > 1)
		{
			depth++;
			n = n / _radix;
		}
		//Node* root = new Node(_radix);
		build(NULL, depth);
	}

	virtual ~StaticTreeBarrier(void)
	{
		delete[] _leaf;
		_leaf = NULL;
	}

	/*
	 * inits that _threadID and _threadSense thread specifics.
	 */
	virtual void initThreadLocals(int);

	/* Barrier's await impl */
	virtual void await();

	inline virtual char* getBarrierName()
	{
		return "StaticTreeBarrier";
	}
private: // StaticTreeBarrier Class
	int _radix;    // tree fan-out
	Node** _leaf;  // array of leaf nodes  instead of this - use stl::vector of POINTER to Node. delete in vector invalidates the iterator.
	int _leaves;   // used to build tree
	int _numOfThreads;

	STBThreadLocal threadSense; // thread-local sense
	STBThreadLocalID threadId;

	volatile int global_sense; // global barrier sense

	// recursive tree constructor
	void build(Node* parent, int depth);
};
